package hermesV3.services.HubService;

import it.unicam.cs.cosy.bioshape.core.util.Messages;
import hermesV3.Message;
import hermesV3.agent.Identifier;
import hermesV3.agent.InteractionContainer;
import hermesV3.agent.ServiceAgent;
import hermesV3.protocols.SynProtocol;
import hermesV3.services.HubAgent;
import hermesV3.services.Space.SpaceManager;
import hermesV3.util.HermesLogger;

/**
 * A {@code Thread} launched by the {@link HubAgent} to parallelize the
 * communication with the {@code PeerAgent}s.<br>
 * Each time a {@code PeerAgent} wants to start a messages exchange with the
 * {@code HubAgent}, the latter launches a new {@code PeeringHandler} which
 * manages the communication setting the {@code HubAgent} free to answer other
 * requests. This approach is practically the same of a web-server waiting for
 * client requests.
 * 
 * @see PeerAgent
 * @see HubAgent
 * @see SpaceManager
 * 
 * @author Federico Buti, Gaston Alanis, Matteo Micheletti, Andrea Piermarteri
 */
public class PeeringHandler extends Thread {

	/** The message received by the {@link ServiceAgent}. */
	private Message<?> msg;
	/** The {@link ServiceAgent} caller. */
	private HubAgent sa;
	private Identifier gc;
	private Identifier sm;
	private Identifier iId;

	/**
	 * A {@link PeeringHandler} thread.
	 * 
	 * @param sa
	 *            The {@link ServiceAgent} that launched the thread. Used to
	 *            send message on its behalf.
	 * @param gc
	 *            The {@link Identifier} of the {@code GeneralCoordinator}
	 *            agent.
	 * @param sm
	 *            The {@link Identifier} of the {@code SpaceManager} agent.
	 * @param iId
	 *            The {@link Identifier} of the {@code SimulationAgent} agent
	 *            controlling the GUI
	 * @param msg
	 *            The message received
	 * 
	 * @see it.unicam.cs.cosy.bioshape.core.components.GlobalCoordinator
	 */
	public PeeringHandler(HubAgent sa, Identifier gc, Identifier sm,
			Identifier iId, Message<?> msg) {
		this.sa = sa;
		this.gc = gc;
		this.sm = sm;
		this.iId = iId;
		this.msg = msg;
	}

	/**
	 * Sends the {@code GlobalCoordinator}, the {@code SpaceManager} and the
	 * {@code SimulationAgent} {@code Identificator}s to the requesting
	 * {@code PeerAgent} to enable communication between the simulation nodes.<br>
	 * Note that <i>NO</i> error handling is applied in this part of the
	 * execution. Possible errors are managed subsequently by the
	 * {@code GlobalCoordinator}.
	 * 
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		InteractionContainer ic = (InteractionContainer) msg.getObject();
		if (ic.getInteractionName().equals(SynProtocol.INTERACTIONSYN)
				&& ic.validate(new SynProtocol())) {
			Object[] params = new Object[] { gc, sm, iId };
			if (!Messages.sendSynAck(sa, msg.getSenderAgentId(), params))
				HermesLogger.log(HermesLogger.WARNING, sa.getClass()
						.getSimpleName()
						+ " - unable to communicate with the 'PeerAgent'. "
						+ "Waiting|replying to other requests.");
		} else
			HermesLogger.log(HermesLogger.WARNING, sa.getClass()
					.getSimpleName()
					+ " - The communication protocol of the 'PeerAgent' is "
					+ "incorrect." + "Waiting|replying to other requests.");
	}
}